package org.sfx.diagnostics

import javafx.scene.Node
import javafx.beans.value.ObservableValue
import javafx.collections.ObservableList
import org.sfx.rich.Enrich._
import scala.collection.JavaConverters._
import org.sfx.collections.CompositeObservableList
import javafx.collections.FXCollections
import javafx.scene.control.TextField
import javafx.event.EventHandler
import javafx.scene.input.KeyEvent
import javafx.scene.input.KeyCode
import javafx.scene.layout.HBox
import javafx.scene.control.Label
import javafx.scene.Scene
import org.sfx.util.Accessor
import org.sfx.util.ObjectGetter
import org.sfx.util.StringGetter
import org.sfx.util.StringSetter

case class SpyInfo(val name: String, val item: Object) {
  def value: Object = item match {
    case null => null
    case observableValue: ObservableValue[Nothing] => observableValue.getValue()
    case x => x
  }
  
  def stringValue: String = itemString
  
  def stringValue_=(value: String): Unit = item match {
    case null => null
    case accessor: StringSetter => {
      println("--> a string")
      accessor.stringValue = value
    }
    case a: Accessor => {
      println("--> something else: " + a.subject)
    }
    case x => {
      x
    }
  }
  
  def isLeaf: Boolean = item match {
    case null => true
    case observableValue: ObservableList[Nothing] => false
    case _ => children.size == 0
  }
  
  def itemString: String = value match {
    case null => "null"
    case accessor: StringGetter => accessor.stringValue
    case x => x.toString()
  }
  
  def kind: SpyKind = item match {
    case control: StringSetter => {
      SpyKind.WritableProperty
    }
    case control: StringGetter => {
      SpyKind.ReadableProperty
    }
    case control: ObservableList[_] => {
      SpyKind.ObservableList
    }
    case _ => SpyKind.ReadableValue
  }

  lazy val children = {
    var composite: CompositeObservableList[SpyInfo] = new CompositeObservableList[SpyInfo]()
    
    if (this.value != null) {
      val list: ObservableList[SpyInfo] = FXCollections.observableArrayList()
      
      this.value match {
        case observableList: ObservableList[_] => {
          observableList.asInstanceOf[ObservableList[Object]].translateInto(list) { thing =>
            SpyInfo("[?]", thing)
          }
        }
        case objectGetter: ObjectGetter => {
          Option(objectGetter.objectValue).map { objectValue =>
            val items1 = objectValue._observableLists.toList.sortBy(_._1).map { case (name, observableList) =>
              SpyInfo(name, observableList)
            }
            list.addAll(items1.asJava)
          }
          
          Option(objectGetter.objectValue).map { objectValue =>
            val items2 = objectValue._properties.toList.sortBy(_.name).map { namedProperty =>
              SpyInfo(namedProperty.name, namedProperty)
            }
            list.addAll(items2.asJava)
          }
        }
        case _ => {
          val items1 = this.value._observableLists.toList.sortBy(_._1).map { case (name, observableList) =>
            SpyInfo(name, observableList)
          }
          list.addAll(items1.asJava)
          
          val items2 = this.value._properties.toList.sortBy(_.name).map { namedProperty =>
            SpyInfo(namedProperty.name, namedProperty)
          }
          list.addAll(items2.asJava)
        }
      }
      
      composite.lists.add(list)
    }
    
    composite
  }
}
